import "./Game.css";
import React from "react";

/**
 *  Define props variable.
 */
interface IProps {}

/**
 *  Define state variable.
 */
interface IState {
  stateRoundOne: number[]; //
  stateRoundTwo: number[];
  stateRoundThree: number[];

  stateResult: string;
  stateProcessing: string;
}

/**
 *  Record game processing state
 */
enum EmunGameState {
  GAMEOVER = "GAMEOVER",
  GAMESTART = "GAMESTART",
  GAMEPROCESSING = "GAMEPROCESSING",
}

/**
 *
 *
 */
class GameRole {
  public name: string; // player name
  public tag:boolean;   // note is first Role

  constructor(name: string,tag:boolean) {
    this.name = name;
    this.tag = tag;
  }

  public getName(): string {
    return this.name;
  }

  public getTag(): boolean {
    return this.tag;
  }

  /**
   * compose processing text
   * @param commotidy The Array of coomedity
   * @param operatorColumn  currently operating column
   * @returns display process text
   */
  public TakeCommidity(commotidy: number[], operatorColumn: number): string {
    const process: string = `用户${this.name},在第${
      operatorColumn + 1
    } 行 ,取出:${commotidy.join(" ")}   <br/>`;

    return process;
  }
}

/**
 *  globle result variable
 */
export const ResultBoard = {
  resultProcess: "",
};

export default class Game extends React.Component<IProps, IState> {
  // private listRound:number[][] = [][0];
  private mapAllRound: Map<number, Array<number>>; // Game data unit

  private currentStep: number; // operating step

  public constructor(props: any) {
    super(props);

    this.mapAllRound = new Map<number, Array<number>>();
    console.log(" Start to initial data.");
    this.currentStep = 0;
    const { roundOne, roundTwo, roundThree } = this.initGameData();
    this.state = {
      stateRoundOne: roundOne,
      stateRoundTwo: roundTwo,
      stateRoundThree: roundThree,
      stateResult: "",
      stateProcessing: "",
    };
  }

  /**
   *  update game board
   */
  public refreshGameBoard() {
    const valRoundOne: number[] = this.mapAllRound.get(0)!;
    const valRoundTwo: number[] = this.mapAllRound.get(1)!;
    const valRoundThree: number[] | undefined = this.mapAllRound.get(2)!;

    this.setState({
      stateRoundOne: valRoundOne,
      stateRoundTwo: valRoundTwo,
      stateRoundThree: valRoundThree,
    });
  }

  /**
   * Calculator ramdom column at first time.
   * @returns ramdom column
   */
  public startStep(): number {
    const listChooseStep = Array.from(Array(this.mapAllRound.size).keys());

    const chooseStep = Math.floor(Math.random() * listChooseStep.length);
    return chooseStep;
  }

  /**
   *
   * @param arr currently user operates column.
   * @param count  commedity number which user takes.
   * @returns
   */
  public getRandomArrayElements(arr: number[], count: number) {
    let shuffled = arr.slice(0),
      totalNum = arr.length,
      min = totalNum - count,
      temp,
      index;

    while (totalNum-- > min) {
      index = Math.floor((totalNum + 1) * Math.random());
      temp = shuffled[index];
      shuffled[index] = shuffled[totalNum];
      shuffled[totalNum] = temp;
    }

    const values: number[] = shuffled.slice(min);

    // Getting commedity index at array list.
    let positions: number[] = [];
    for (let index = 0; index < arr.length; index++) {
      const element = arr[index];
      for (let y = 0; y < values.length; y++) {
        const selectedCommidity = values[y];
        if (selectedCommidity === element) {
          positions.push(index);
        }
      }
    }

    return { randomCommdityPosition: positions, values };
  }

  public processGameFlows(user: GameRole) {
   
    // First time to play game. Getting a random number. otherwise we needn't concern it
    if(user.getTag()) {
      this.currentStep = this.startStep();    
    }
                 

    let totalCommedity: number[] = [];   
    
    //  Calculator total commedity
    this.mapAllRound.forEach((value, key) => {
      totalCommedity = totalCommedity.concat(value);
    });

    const sizeCommedity = totalCommedity.length;

    console.log(`sizeCommedity: ${sizeCommedity}`);

    // skip game loop,  game over.
    if (sizeCommedity === 0) {
      return EmunGameState.GAMEOVER;
    }

    let listArray: number[] | undefined = [];

    // Calculator operator column
    do {
      listArray = this.mapAllRound.get(this.currentStep);

      console.log(`当前在第${this.currentStep}行, 长度${listArray?.length}`)

      if (listArray?.length === 0) {
        this.currentStep = this.currentStep + 1;

        if (this.currentStep === 3) {
          this.currentStep = 0;
        }
      } else {
        break;
      }
    } while (true);

    if (listArray && listArray?.length > 0) {
      let randomTakeNumber = Math.ceil(Math.random() * listArray.length);

      // Please keep one commodity when there is only one line

      if (randomTakeNumber === sizeCommedity && randomTakeNumber >= 2) {
        randomTakeNumber = randomTakeNumber - 1;
      }
      // console.log(`计划要取的个数:${randomTakeNumber}`);
      // console.log(`当前要取的数组:${listArray}`);
      const { randomCommdityPosition, values } = this.getRandomArrayElements(
        listArray,
        randomTakeNumber
      );

      console.log(
        "实际取出数据: %s 个, value: %s, 第%s行",
        randomTakeNumber,
        values.join(" "),
        this.currentStep
      );

      const retProcess = user.TakeCommidity(values, this.currentStep);

      ResultBoard.resultProcess = `${ResultBoard.resultProcess}  ${retProcess}`;

      this.setState({
        stateProcessing: ResultBoard.resultProcess,
      });

      // romove operator element.
      for (let index = 0; index < values.length; index++) {
        for (let j = 0; j < listArray.length; j++) {
          const element = listArray[j];
          if (element === values[index]) {
            listArray.splice(j, 1);
          }
        }
      }

      // Updating board
      this.refreshGameBoard();

      this.currentStep = this.currentStep + 1;

      if (this.currentStep === 3) {
        this.currentStep = 0;
      }
    }

    return EmunGameState.GAMEPROCESSING;
  }

  public startPlayGame() {
    // console.log("startPlayGame");

    const firstPlayRole = new GameRole("第一玩家",true);
    const secondPlayRole = new GameRole("第二玩家",false);

    do {
      const retFirstPlayRole = this.processGameFlows(firstPlayRole); //
      if (retFirstPlayRole === EmunGameState.GAMEOVER) {
        // console.log("玩家一获胜");
        this.setState({
          stateResult: "玩家一获胜",
        });
        break;
      }
      const retSecondPlayRole = this.processGameFlows(secondPlayRole); //
      if (retSecondPlayRole === EmunGameState.GAMEOVER) {
        // console.log("玩家二获胜");
        this.setState({
          stateResult: "玩家二获胜",
        });
        break;
      }
    } while (true);

    console.log("game over");
  }

  public resetGame() {
    this.updateBoard();
  }

  public initGameData() {
    const staticRoundOne = [1, 2, 3];
    const staticRoundTwo = [4, 5, 6, 7,8];
    const staticRoundThree = [9, 10, 11, 12, 13, 14, 15];
    this.mapAllRound.set(0, staticRoundOne);
    this.mapAllRound.set(1, staticRoundTwo);
    this.mapAllRound.set(2, staticRoundThree);

    return {
      roundOne: staticRoundOne,
      roundTwo: staticRoundTwo,
      roundThree: staticRoundThree,
    };
  }

  public updateBoard() {
    if (this.mapAllRound) {
      this.mapAllRound.clear();
    }

    ResultBoard.resultProcess = "";

    const { roundOne, roundTwo, roundThree } = this.initGameData();

    this.setState({
      stateRoundOne: roundOne,
      stateRoundTwo: roundTwo,
      stateRoundThree: roundThree,
      stateResult: "",
      stateProcessing: "",
    });
  }

  render() {
    return (
      <div className="App">
        <div className="board">
          15个任意物品（可以是火柴牙签poker）, 以下按牙签为例 ,将15根牙签, 分成三行,
          每行自上而下（其实方向不限）分别是3、5、7根,
          安排两个玩家，每人可以在一轮内，在任意行拿任意根牙签，但不能跨行,
          拿最后一根牙签的人即为输家.
          题目:
          请用你最擅长的语言，以你觉得最优雅的方式写一个符合以上游戏规则的程序。完成后把写好的代码和简历同时发到以下邮箱（备注姓名+岗位），并加上一段简短的文字描述一下你的想法
          （请使用javascript，typescript或C#的其中一种语言完成测试题）
        </div>

        <div className="board">
          <p>1,2,3</p>
          <p>4,5,6,7,8,</p>
          <p>9,10,11,12,13,14,15</p>
        </div>

        <div className="board">
          <button className="square" onClick={() => this.startPlayGame()}>
            点击开始游戏
          </button>

          <button className="square" onClick={() => this.resetGame()}>
            重置游戏
          </button>
        </div>
        <br></br>
        <div className="result">
          结果: <div style={{ color: "red" }}>{this.state.stateResult}</div>
        </div>

        <br></br>
        <div className="processing">
          运行过程:
          <br></br>
          <div
            dangerouslySetInnerHTML={{ __html: this.state.stateProcessing }}
          ></div>
        </div>
      </div>
    );
  }
}
